﻿#pragma once

#include <cassert>
#include <vector>

// Eigen 库
#include <Dense>
#include <Eigenvalues>
#include <Sparse>
#include <random>

#undef Handle

#include <occmesh/api/meshdef.h>
#include <occmesh/api/timing.h>

#define Handle(Class) opencascade::handle<Class>

// OCC 库（注意库的引用顺序，必须放在后面）
#include <BRepBuilderAPI_MakeEdge.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <BRepBuilderAPI_MakeWire.hxx>
#include <BRepTools.hxx>
#include <BRep_Builder.hxx>
#include <BRep_Tool.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <Geom2dAPI_Interpolate.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Curve.hxx>
#include <GeomAPI_Interpolate.hxx>
#include <GeomAPI_ProjectPointOnSurf.hxx>
#include <GeomAdaptor_Curve.hxx>
#include <GeomLProp_SLProps.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_BSplineSurface.hxx>
#include <STEPControl_Reader.hxx>
#include <STEPControl_Writer.hxx>
#include <TColStd_HArray1OfReal.hxx>
#include <TColgp_HArray1OfPnt.hxx>
#include <TColgp_HArray1OfPnt2d.hxx>
#include <TColgp_SequenceOfPnt.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Wire.hxx>

#undef near
#undef far
#undef min
#undef max

class OCCUtils
{
  public:
    static std::vector<gp_Vec> OBB(const std::vector<gp_Pnt> &points);

    static int FindSpan(double u, int p, const std::vector<double> &knots);
    static std::vector<double> BasisFuncs(int i, double u, int p, const std::vector<double> &knots);
    static std::vector<std::vector<double>> DerivBasisFuncs(int d, int i, double u, int p,
                                                            const std::vector<double> &knots);

    static Handle(Geom2d_Curve) Interpolate(const std::vector<gp_Pnt2d> &points);
    static Handle(Geom_Curve) Interpolate(gp_Pnt P0, gp_Pnt P1, gp_Vec V0, gp_Vec V1);
    static void CompatCurves(Handle(Geom_BSplineCurve) c1, Handle(Geom_BSplineCurve) c2);

    static std::vector<double> ChordParameterize(const std::vector<gp_Pnt2d> &points);
    static std::vector<gp_Pnt2d> ProjectParameterize(const std::vector<gp_Pnt> &points);
    static TopoDS_Wire TrimmSurface(Handle(Geom_Surface) surface, const std::vector<Handle(Geom2d_Curve)> &curves);

    static double ProjectWithOCC(Handle(Geom_Surface) surf, gp_Pnt P, double &u, double &v);
    static double ProjectWithNearest(Handle(Geom_Surface) surface, gp_Pnt P, double &u, double &v, double tol);
    static double ProjectWithOrtho(Handle(Geom_Surface) surface, gp_Pnt P, double &u, double &v, double tol);

    // 弦长最小化拟合曲面
    static Handle(Geom_BSplineSurface) Chord(const std::vector<gp_Pnt> &cloud, std::vector<gp_Pnt2d> &uv, int Nu,
                                             int Nv, int p, int q, std::vector<double> &w, double alpha, double beta);

    static Handle(Geom_Curve) FindVertex(const TopoDS_Edge edge, const TopoDS_Vertex vertex, gp_Pnt &P, gp_Vec &V);
    static double SurfaceEnergy(Handle(Geom_BSplineSurface) surface);
    static std::tuple<double, double> MeasureDivation(Handle(Geom_BSplineSurface) surface,
                                                      const std::vector<Handle(Geom_Curve)> &boundaryCurves,
                                                      const std::vector<Handle(Geom_Surface)> &boundarySurfaces);
    static void CurveInfo(Handle(Geom_BSplineCurve) curve);
    static void SurfaceInfo(Handle(Geom_BSplineSurface) surface);

    // 生成测试网格
    static bool Tag(std::vector<std::vector<int>> &tags, int tag, int si, int sj, int depth);
    static MeshPtr GenerateRandomMesh(int size, int holes, std::function<Mesh::Point(double u, double v)> f);
    static MeshPtr GenerateTestMesh(int size, int holes, std::function<int(const std::vector<gp_Pnt> &)> generator);

    static std::vector<std::tuple<TopoDS_Edge, TopoDS_Face>> GetAdjFaces(const TopoDS_Face &face,
                                                                         const TopoDS_Shape &shape);
    static std::vector<std::tuple<TopoDS_Edge, TopoDS_Face>> GetAdjFaces(const std::vector<TopoDS_Edge> &edges,
                                                                         const TopoDS_Shape &shape);
    static std::vector<TopoDS_Edge> GetEdgesInOrder(const std::vector<TopoDS_Edge> &shapes, int samples);
    static void WriteCloud(const std::vector<gp_Pnt> &points, const char *path);
    static TopoDS_Shape WirteAndRead(const TopoDS_Shape &shape, const char *path);

  public:
    static std::vector<std::vector<double>> gaussNodes;
    static std::vector<std::vector<double>> gaussWeights;
    static std::vector<double> gaussNodes64;
    static std::vector<double> gaussWeights64;
};
